
from common.data_struct import *
from api.swift_policy import *
class PolicyEngine(object):
	"""docstring for PolicyEngine"""
	def __init__(self):
		self.policy_store=[]
		self.op=Operation()
		self.ac=Attribute()
		self.st_table={}
		self.cache={}
		self.rs_table={}
		self.delay=5.0
		pass

	def parse_policy(self,p):
		for tp in p:
			self.policy_store.append(tp)
		pass

	def save_state(self,meta):
		import hashlib
		#h=str(meta)
		h=hashlib.sha224(str(meta)).hexdigest()
		if h in self.st_table:
			up_flag=False
			if self.st_table[h]['reset']:
				if time.time()>self.st_table[h]['reset_time']+self.delay:
					print "reset finish"
					self.st_table[h]['reset']=False
					self.st_table[h]['rate']=0
					self.st_table[h]['count']=1
					self.st_table[h]['s_time']=time.time()
					self.st_table[h]['c_time']=time.time()
					up_flag=True
					return h
			else:
				up_flag=True
			if up_flag:
				ct=time.time()
				st=self.st_table[h]['s_time']
				cn=self.st_table[h]['count']
				self.st_table[h]['count']=cn+1
				self.st_table[h]['rate']=cn/(ct-st)
				self.st_table[h]['c_time']=ct
		else:
			self.st_table[h]={}
			self.st_table[h]['count']=1
			self.st_table[h]['c_time']=time.time()
			self.st_table[h]['s_time']=time.time()
			self.st_table[h]['rate']=0
			self.st_table[h]['reset']=False
		return h

	def clear_state_field(self,h,field):
		if h in self.st_table:
			self.st_table[h][field]=1

			self.st_table[h]['reset']=True
			self.st_table[h]['reset_time']=time.time()

	def do_action(self,r,meta):
		gr=r[0]
		ar=r[1]
		print r
		if gr!=None:
			if gr=="META":
				print "call logger"
				rs=meta[1]
				o={}
				o["owner"]=rs["owner"]
				o["type"]=rs["type"]
				o["create_time"]=rs["create_time"]
				o["modify_time"]=o["create_time"]
				o["obj"]=rs["obj"]
				o["container"]=rs["container"]
				if o["obj"]:
					_id="#".join((o["owner"],o["container"],o["obj"]))
					self.rs_table[_id]=o
					print "resource",self.rs_table
				
		#if ar==None:
			#print "call controller"
		return str(ar)

	def lookup(self,meta):
		r1=r2=None
		h=self.save_state(meta)
		for tp in self.policy_store:
			if tp['Global']:
				res=self.lookup_one(tp,h,meta,1)
				if res:
					if not tp["Condition"]:
						r1=tp['Decision']
						break
					else:
						if not self.lookup_cond(tp,h):
							r1="DENY"
						else:
							r1=tp['Decision']
							break
				#if res==False:
				#	r1="DENY"
				#	break
						
		for tp in self.policy_store:
			if not tp['Global']:
				res=self.lookup_one(tp,h,meta,0)
				if res:
					if not tp["Condition"]:
						r2=tp['Decision']
						break
					else:
						if not self.lookup_cond(tp,h):
							r2="DENY"
						else:
							r2=tp['Decision']
							break
				#if res==False:
				#	r2="DENY"
				#	break

		return self.do_action((r1,r2),meta)
		
	def lookup_one(self,p,h,meta,gl):
		pid=p["id"]
		if (h,gl,pid) in self.cache:
			return self.cache[(h,gl,pid)]
		action=meta[2]['action'].lower()
		all_match=True
		targets=['Subject','Resource']
		for kw in (0,1) :
			tp=p[targets[kw]]
			if not tp:
				continue
			for k in tp:
				if k in meta[kw]:
					v=str(meta[kw][k])

					for r in tp[k]:
						op=r["op"]
						tv=r["value"]
						c=self.ac.attr_info[targets[kw]][k]
						if not self.op.compare(v,op,tv,c):
							print v,tv
							self.cache[(h,gl,pid)]=False
							return False
				else:
					all_match=False
			"""
			if not tp:
				continue
			for k in meta[kw]:
				v=str(meta[kw][k])
				if k in tp:
					#match one field
					for r in tp[k]:
						op=r["op"]
						tv=r["value"]
						c=self.ac.attr_info[targets[kw]][k]
						if not self.op.compare(v,op,tv,c):
							self.cache[(h,gl,pid)]=False
							return False
				else:
					all_match=False
			"""
		if not action in p['Action']:
			self.cache[(h,gl,pid)]=False
			return False

		if all_match:
			self.cache[(h,gl,pid)]=True
			return True
		self.cache[(h,gl,pid)]=None
		return None

	def lookup_cond(self,p,h):

		tp=p['Condition']
		for k in tp:
			for r in tp[k]:
				tv=float(r['value'])
				op=r['op']
				if k=="interval":
					if not self.st_table[h][count]%tv==0:
						return False
				else:
					v=float(self.st_table[h][k])
					if not self.op.compare(v,op,tv,k):
						self.clear_state_field(h,k)
						return False
					elif self.st_table[h]['reset']==True:
						return False
		return True

if __name__ == '__main__':
	import cPickle
	from random import randrange
	p=cPickle.load(open("test1.po"))
	PE=PolicyEngine()
	PE.parse_policy(p)
	meta=[{'ip': u'127.0.0.1', 'account': u'test', 'uid': u'test:test1', 'user': u'test1'}, {'owner': u'test:test1', 'obj': None, 'container': u'proj1', 'type': None}, {'action': u'GET'}]
	PE.lookup(meta)